package com.morningstar.flow.service;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.morningstar.flow.dao.entity.FlowNodeInstance;
import com.morningstar.flow.dao.mapper.FlowNodeInstanceMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.event.impl.FlowableActivityEventImpl;
import org.flowable.engine.runtime.Execution;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Slf4j
@Service
public class FlowNodeInstanceService extends ServiceImpl<FlowNodeInstanceMapper, FlowNodeInstance> {

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private FlowNodeInstanceMapper flowNodeInstanceMapper;

    /**
     * 流程节点创建
     *
     * @param flowableActivityEvent event
     */
    public void create(FlowableActivityEventImpl flowableActivityEvent) {
        String executionId = StringUtils.equalsIgnoreCase(flowableActivityEvent.getActivityType(), "UserTask")
                ? flowableActivityEvent.getExecution().getParentId() : flowableActivityEvent.getExecutionId();
        FlowNodeInstance flowNodeInstance = new FlowNodeInstance();
        flowNodeInstance.setProcessInstanceId(flowableActivityEvent.getProcessInstanceId());
        flowNodeInstance.setExecutionId(executionId);
        flowNodeInstance.setNodeActivityId(flowableActivityEvent.getActivityId());
        flowNodeInstance.setAgree(0);
        flowNodeInstance.setRefuse(0);
        flowNodeInstance.setStatus("1");
        flowNodeInstance.setCreateTime(LocalDateTime.now());
        this.save(flowNodeInstance);
    }

    /**
     * 节点结束
     * todo 只有开始节点更新成功
     *
     * @param flowableActivityEvent flowableActivityEvent
     */
    public void end(FlowableActivityEventImpl flowableActivityEvent) {
        LambdaUpdateWrapper<FlowNodeInstance> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(FlowNodeInstance::getExecutionId, flowableActivityEvent.getExecutionId());
        updateWrapper.eq(FlowNodeInstance::getNodeActivityId, flowableActivityEvent.getActivityId());
        updateWrapper.eq(FlowNodeInstance::getProcessInstanceId, flowableActivityEvent.getProcessInstanceId());
        updateWrapper.set(FlowNodeInstance::getStatus, "2");
        updateWrapper.set(FlowNodeInstance::getEndTime, LocalDateTime.now());
        this.update(updateWrapper);
    }

    /**
     * 更新审批统计
     *
     * @param task  任务
     * @param audit 审批意见
     */
    @Transactional(rollbackFor = Exception.class)
    public void completeTask(Task task, Object audit) {
        Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
        if (execution == null) {
            log.info("completeTask 未找到执行实例 {}", task.getExecutionId());
            return;
        }
        String executionId = execution.getParentId();
        if (StringUtils.isBlank(executionId)) {
            log.info("completeTask 未找到执行实例父ID {}", task.getExecutionId());
            return;
        }
        Boolean agree = (Boolean) audit;
        if (agree) {
            flowNodeInstanceMapper.addAgree(executionId, task.getProcessInstanceId(), task.getTaskDefinitionKey());
            return;
        }
        flowNodeInstanceMapper.addRefuse(executionId, task.getProcessInstanceId(), task.getTaskDefinitionKey());
    }

    /**
     * 获取同意数量
     *
     * @param executionId 流程执行Id
     * @return 同意数量
     */
    public Integer getAgree(String executionId) {
        FlowNodeInstance nodeInstance = this.lambdaQuery()
                .eq(FlowNodeInstance::getExecutionId, executionId)
                .one();
        if (nodeInstance == null) {
            throw new RuntimeException("未查询到流程节点统计数据");
        }
        return nodeInstance.getAgree();
    }
}
